package com.divemotor.ventarepuestosinternet.dao.impl;


import java.io.Serializable;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.hibernate.transform.Transformers;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.hibernate.type.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.divemotor.ventarepuestosinternet.beans.adapter.UsuarioInternoAdapter;
import com.divemotor.ventarepuestosinternet.beans.form.UsuarioInternoBeanForm;
import com.divemotor.ventarepuestosinternet.dao.UsuarioDAO;
import com.divemotor.ventarepuestosinternet.model.Usuario;
import com.divemotor.ventarepuestosinternet.util.Constantes;
import com.divemotor.ventarepuestosinternet.util.DatosDeSession;

@SuppressWarnings("unchecked")
@Repository (value = "usuarioDAO")
public class UsuarioDAOImpl implements UsuarioDAO, Serializable {
	
	private static final long serialVersionUID = 548640635129039483L;
	
	@Autowired
	private SessionFactory sessionFactory;
	
	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	@Override
	public void insertar(Usuario usuario) {
		getSessionFactory().getCurrentSession().persist(usuario);
	}
	
	@Override
	public void actualizar(Usuario usuario) {
		 getSessionFactory().getCurrentSession().merge(usuario);
	}
	
	@Override
	public void eliminar(Usuario usuario)  {
		getSessionFactory().getCurrentSession().merge(usuario);
	}
	
	@Override
	public Usuario obtenerPorId(Integer idUsuario) {
		return (Usuario)getSessionFactory().getCurrentSession().get(Usuario.class, idUsuario);
	}
	
	@Override
	public Usuario obtenerReferenciaPorId(Integer idUsuario) {
		return (Usuario)getSessionFactory().getCurrentSession().load(Usuario.class, idUsuario);
	}
	
	public Usuario obtenerPorSolicitud(Integer idSolicitud){
		Query q = sessionFactory.getCurrentSession().getNamedQuery("Usuario.getSolicitud");
		q.setParameter("idSolicitud", idSolicitud);
		return (Usuario)q.uniqueResult();
	}

	@Override
	public Usuario obtenerPorUsuarioLogin(Usuario usuario)  {
		Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(Usuario.class);
		criteria.add(Restrictions.eq("usuario", usuario.getUsuario()).ignoreCase());
        return (Usuario)criteria.uniqueResult();
	}
	
	@Override
	public List<Usuario> listar() {
		return getSessionFactory().getCurrentSession().createQuery("from Usuario").list();
	}
	
	@Override
	public List<Usuario> listarPorPropiedad(String propiedad, Object value) {
		return sessionFactory.getCurrentSession().createCriteria(Usuario.class).add(Restrictions.eq(propiedad, value).ignoreCase()).list();
	}
	
	@Override
	public void actualizarUsuarioExistente(Usuario usuario) {
		getSessionFactory().getCurrentSession().merge(usuario); 
		getSessionFactory().getCurrentSession().flush();
	}

	@Override
	public Usuario obtenerListadePerfiles(Usuario usuario) {
		Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(Usuario.class);
		criteria.add(Restrictions.eq("idUsuario", usuario.getIdUsuario()));
		criteria.add(Restrictions.eq("pais", usuario.getPais()));
		return (Usuario)criteria.uniqueResult();
	}
	
	@Override
	public Usuario obtenerPorUsuarioLoginSistema(String usuario){
		Session session = getSessionFactory().getCurrentSession();
		session.enableFilter("perfiles").setParameter("idSistema", Constantes.ID_SISTEMA_ACTUAL);
		Query q = session.getNamedQuery("Usuario.sistema");
		q.setParameter("usuario", usuario);
		q.setParameter("sistema", Constantes.ID_SISTEMA_ACTUAL);
		return (Usuario) q.uniqueResult();
	}
	
	public List<UsuarioInternoAdapter> listarUsuariosInternos(UsuarioInternoBeanForm usuInternoForm){
		Criteria criteria 					= null;
		List<UsuarioInternoAdapter> lista 	= null;
		Integer idPerfil 					= usuInternoForm.getIdPerfil();
		Integer sucursal					= null;
		String  perfil						= null;
		String  idUsuarioPerfil				= null;
		
		if(idPerfil!=null){
			Session sesion 	= sessionFactory.getCurrentSession();
			criteria 		= sesion.createCriteria(Usuario.class, "usuario");
			criteria.createAlias("usuario.listaPerfiles", "perfil");
			criteria.createAlias("perfil.sistema", "sistema");
			
			switch(idPerfil){
				case 4:
					criteria.createAlias("usuario.administradores", "interno", JoinType.INNER_JOIN);
					perfil 			= "Administrador";
					idUsuarioPerfil	= "idAdministrador";
					break;
					
				case 5:
					criteria.createAlias("usuario.vendedores", "interno", JoinType.INNER_JOIN);
					perfil 			= "Vendedor";
					idUsuarioPerfil	= "idVendedor";
					
					sucursal = usuInternoForm.getIdSucursal();
					if(sucursal!=null && !Constantes.NO_SELECCIONADO.equals(sucursal)){
						criteria.add(Restrictions.eq("interno.sucursal.idSucursal", sucursal));
					}
					
					break;
					
				case 6:
					criteria.createAlias("usuario.supervisores", "interno", JoinType.INNER_JOIN);
					perfil 			= "Supervisor";
					idUsuarioPerfil	= "idSupervisor";
					
					sucursal = usuInternoForm.getIdSucursal();
					if(sucursal!=null && !Constantes.NO_SELECCIONADO.equals(sucursal)){
						criteria.createAlias("supervisor.listaSucursal", "suc");
						criteria.add(Restrictions.eq("suc.idSucursal", sucursal));
					}
					
					break;
			}
			construirProyeccion(criteria, perfil, idUsuarioPerfil, idPerfil);
			construirRestriccion(usuInternoForm, criteria);
			criteria.setResultTransformer(Transformers.aliasToBean(UsuarioInternoAdapter.class));
			lista = criteria.list();
		}
		
		return lista;
	}
	
	private void construirProyeccion(Criteria criteria, String perfil, String idUsuarioPerfil, Integer idPerfil){
		ProjectionList lista = Projections.projectionList();
		lista.add(Projections.property("idUsuario"), "idUsuarioInterno");
		lista.add(Projections.property("interno." + idUsuarioPerfil), "idUsuarioPerfil");
		lista.add(Projections.property("usuario"), "usuario");
		lista.add(Projections.property("nombres"), "nombres");
		lista.add(Projections.property("apellidos"), "apellidos");
		lista.add(Projections.property("interno.estado"), "estado");
		lista.add(Projections.sqlProjection("'" + perfil + "' as perfil", 
											new String[]{"perfil"}, new Type[]{new StringType()}), "perfil");
		lista.add(Projections.sqlProjection(idPerfil + " as idPerfil", 
											new String[]{"idPerfil"}, new Type[]{new IntegerType()}), "idPerfil");
		criteria.setProjection(lista);
	}
	
	private void construirRestriccion(UsuarioInternoBeanForm usuInternoForm, Criteria criteria){
		String cons = Constantes.PORCENTAJE;
		
		String nombre 	= usuInternoForm.getNombre();
		if(StringUtils.isNotBlank(nombre)){
			criteria.add(Restrictions.like("nombres", cons + nombre + cons));
		}
		
		String apellido = usuInternoForm.getApellido();
		if(StringUtils.isNotBlank(apellido)){
			criteria.add(Restrictions.like("apellidos", cons + apellido + cons));
		}
		
		String usuario	= usuInternoForm.getUsuario();
		if(StringUtils.isNotBlank(usuario)){
			criteria.add(Restrictions.like("usuario", cons + usuario + cons));
		}
		
		String estado	= usuInternoForm.getEstado();
		if(StringUtils.isNotBlank(estado) && !Constantes.STR_NO_SELECCIONADO.equals(estado)){
			criteria.add(Restrictions.eq("interno.estado", estado));
		}
		
		criteria.add(Restrictions.eq("pais", DatosDeSession.obtenerPaisDelUsuarioAutenticado()));
		criteria.add(Restrictions.not(Restrictions.eq("interno.estado", Constantes.ESTADO_ELIMINADO)));
		criteria.add(Restrictions.eq("sistema.idSistema", Constantes.ID_SISTEMA_ACTUAL));
	}
	
}
